<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<!-- 
		父 - 子
		
		子 - 父   $emit    子组件 通过 $emit 出发自定义事件 传递参数   父组件通过绑定改自定义事件 得到数据
		
		爷 - 孙 (隔代)   provide  inject    $attr  $linsten
		 
		任意组件    eventBus   new Vue()    订阅者发布模式  pubsic.js
		
		
		
		
		 一、什么是vuex？
		 按照官网的说法，Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
		 它采用集中式存储管理应用的所有组件的状态，并以相应的规则保证状态以
		 一种可预测的方式发生变化。
		 
		 1.vuex的组成 
		 vuex由五个部分组成，分别是State，Mutation，Action，Module，Getter。
		 
		 属性	解释
		 State	共享状态（即变量）
		 Mutation	更改vuex的store中state的唯一方法，只有通过提交mutation才能修改状态（变量值)
		 Action	类似mutation，修改store中的状态。但是刚才说过只有通过提交mutation才能修改状态，所以Action也是通过提交mutation修改store中的状态 ，与Mutataion不同的是Action支持异步操作
		 Module	模块，在大型项目中为了方便状态的管理和协作开发将store拆分为多个子模块（modules），每个子模块拥有完整的state、mutation、action、getter。（这里先不介绍）
		 Getter	基于state的派生状态，可理解为组件中的计算属
		 
		 2.为什么使用vuex？
		 多个视图依赖于同一状态
		 
		 来自不同视图的行为需要变更同一状态
		 
		 对于问题一，传参的方法对于多层嵌套的组件将会非常繁琐，并且对于兄弟组件间的状态传递无能为力。
		 
		 对于问题二，我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱，通常会导致无法维护的代码。
		 
		 其实vuex通俗点可以理解为响应式的全局变量，
		 
		 3.什么情况下使用 vuex？
		 Vuex 可以帮助我们管理共享状态，并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
		 如果您不打算开发大型单页应用，使用 Vuex 可能是繁琐冗余的。但是，如果您需要构建一个中大型
		 单页应用，您很可能会考虑如何更好地在组件外部管理状态，Vuex 将会成为自然而然的选择。
		
		 
		二、vuex的使用
		1.vuex安装（需先安装vue-cli）
			cd到自己的项目目录下
			输入命令：npm install vuex -S
			注意  vue2 只能使用  vuex的版本3.xx   
			如果用是vuex@4 ，重新安装vuex@3 
			cnpm uninstall vuex  -S
			cnpm install vuex@3 -S  
		
		2.首先，新建好所需文件夹和文件，以供等下的学习使用。
		在src目录下新建文件夹store
		在该文件夹里面 新建 一个 index.js
			import vuex from "vuex"
			import vue from 'vue'
			vue.use(vuex)
			console.log(vuex);
			const store = new vuex.Store({
				state:{
					num:0
				}
			})
			export default store
		
		3.然后进行配置
		（1）然后在main.js里面 挂载 store
			import store from '@/store'
			new Vue({
				store,
			  render: h => h(App),
			}).$mount('#app')
		
		vueX五大板块的功能
		const store = new vuex.Store({
			//存储初始化的数据
			state:{
				num:0
			},
			//state里面的数据只能通过mutations修改
			//mutations里面的方法 需要在组件里面 通过this.$store.commit('changeNum',1)调用
			//this.$store.commit()函数需要两个参数  第一个就是 调用的方法名 第二个 就是	
			mutations:{
				changeNum(state,arg){
					//state 代表  store里面的 state 本身   arg  就是 commit传入的第二个参数
					console.log('触发了 mutations里面的changeNum',state,arg);
					state.num+=arg
				}
			},
			//actions里面的方法 需要在组件里面 通过this.$store.dispatch('changeNum',1)调用
			//this.$store.dispatch()函数需要两个参数  第一个就是 调用的方法名 第二个 就是传入的数据
			actions:{
				changeNum(inStore,arg){
					//inStore 代表  store 本身   arg  就是 dispatch传入的第二个参数
					setTimeout(()=>{
						console.log(inStore,arg);
						inStore.commit('changeNum',arg)
					},2000)
				}
			},
			//从里面可以得到 state里面的数据 计算过后的结果
			getters:{
				newNum(state){
					return state.num*50
				}
			},
			//子store的挂载位置
			modules:{
				userStore
			}
		})
		
		export default store
		
		export default {
			namespaced: true,//命名空间namespaced: true
			state: {
				st1:'张三',
				st2:"李四"
			},
			mutations: {
			},
			actions: {
			}
		}
		
		
		
		
		 
		三.优化与注意点 
		getter 不会修改state 包装 重新返回
		dispath(fn,arg)  调用 Actions 里面的方法
		commit(fn,arg)   Mutation修改 state
		
		****///***
		0.通过计算属性使用 数据 
		num:{
			get(){
				return this.$store.state.num
			},
			set(val){
				this.$store.commit('changNum',val)
			}
		}
		****///***
		
		
		
		
		*****映射*****
		1.mapState  映射 state 到 computed
		mapState 方法 接受一个参数 为数组 数组里面 写入需要映射的state里面 的属性名
		import {mapState} from 'vuex'
		computed:{
			...mapState(['num'])
		},
		
		2.mapMutations  映射 Mutation 到 methods
		mapMutations 方法 接受一个参数 为数组 数组里面 写入需要映射的Mutations里面 的方法名
		import {mapMutations} from 'vuex'
		methods: {
			...mapMutations(['changeNum']),
		}
	
		3.mapActions  映射 Actions 到 methods
		mapActions 方法 接受一个参数 为数组 数组里面 写入需要映射的Actions里面 的方法名
		import {mapActions} from 'vuex'
		methods: {
			...mapActions(['syncChangeNum'])
		}
		
		4.mapGetters 映射  getters 到 computed里面 
		mapGetters 方法 接受一个参数 为数组 数组里面 写入需要映射的getter里面 的属性名
		import {mapGetters} from 'vuex'
		computed:{
			...mapGetters(['newNum'])
		},
		
		5.modules里面的数据的映射  
		
		//modules里面使用其他模块
		//modules里面的store必须加上命名空间namespaced: true
		store文件夹里面 新建一个 name.js  写入一下内容  
		export default {
			namespaced: true,//命名空间namespaced: true
			state: {
				st1:'张三',
				st2:"李四"
			},
			mutations: {
			},
			actions: {
			}
		}
		
		在 index.js 里面   主的vuex里面 引入
		import name from './name.js'
		const store = new vuex.Store({
			state:...,
			mutations:...,
			actions:...,
			getters:...,
			modules:{
				name
			}
		})
		
		
		子模块的映射
		import {createNamespacedHelpers} from 'vuex'
		const { mapState, mapMutations, mapActions, mapGetters } =createNamespacedHelpers("模块名"); 
		computed:{
			...mapGetters(['newNum'])
		}
		
		或者  
		import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'
		...mapState('cartModule', ['cart'])
		...mapMutations('cartModule', ['delCartItem'])
		 
		 
		 
		 
		四.vuex数据持久化
		但是大家都知道 vuex 的数据页面刷新就会丢失，都是通过手动存入本地缓存中来解决数据刷新丢失的问题，
		稍显麻烦。有一个插件 vuex-persistedstate 可以解决这个问题。

		vuex-persistedstate 使用浏览器的本地存储（ local storage ）对状态（ state ）进行持久化。
		这意味着刷新页面或关闭标签页都不会删除你的数据。
		
		如何使用  
		① npm install vuex-persistedstate --save
		
		②在 store 中引入 vuex-persistedstate
		import createPersistedState from 'vuex-persistedstate'
		③
		export default new Vuex.Store({
			state: {
			},
			getters: {
			},
			mutations: {
			},
			actions: {},
			modules: {},
			plugins: [createPersistedState()]
		}) 
		 
		 
		 五.关于vuex里面 需要注意的地方 
		 1.mutation 跟action的区别?
		 mutation 只能写同步操作
			mutation 也能写异步操作 不影响页面 但是会影响的 vue-dev 里面 保存的vuex的状态
				也就是说 vuex的持久化 会出错
		action 写异步的操作 ,但是也能写同步
		action 里面 不能直接 修改state 必须 通过 commit  context.commit('changeNum',66)
		 为什么?
		 
		 
		 总结  mutation 跟action的区别? 
		  ① mutation 只能写同步操作  action 写异步的操作  
			②  action 里面 不能直接 修改state 必须 通过 commit 调用mutations里面的方法
			如果不区分mutation 跟action 有什么后果?
			① 看起来对页面并没有什么影响
			② vuex持久化失效
			③ vuedetool 里面  vuex 历史记录 失效
		 -->
	</body>
</html>
